﻿using MHI.ScenarioManager.Data;
using MHI.ScenarioManager.Interfaces;
using MHI.Utility;
using WebFoundation;
using WebFoundation.Data;
using WebFoundation.GenericModules.Interfaces;
using WebFoundation.Settings;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace MHI.ScenarioManager.Business
{
    internal class ScenarioModule : WFModule, IScenarioModule
    {
        private DbManager _dbManager;
        private readonly ScenarioQueryDAO _scenarioQueryDAO;
        private readonly ScenarioWritingDAO _scenarioWriteDAO;
        private static object lockObjet = new object();

        public static string GetModelType(enumScenarioType scenarioType)
        {
            switch (scenarioType)
            {
                case enumScenarioType.SWMMModel:
                    return "MHI.ThirdPartyModel.SWMM.SWMMModel, MHI.ThirdPartyModel.SWMM";
                case enumScenarioType.EFDCModel:
                    return "MHI.ThirdPartyModel.EFDC.EFDCModel, MHI.ThirdPartyModel.EFDC";
                case enumScenarioType.WaterForecastModel:
                    return "MHI.Generic.WaterForecast.WaterForecastModel, MHI.Generic.WaterForecast";
                default:
                    return "";
            }
        }

        public ScenarioModule()
        {
            _dbManager = DbManager.FromConfig();
            string workFolder = WFAppSettings.GetDefaultConfig().ReadValue(Scenario.WorkFolderAppSettingCode);
            ;
            if (workFolder != string.Empty)
            {
                MHI.Environment.Environment.LocalWorkingFolder = workFolder;
                MHI.Environment.Environment.Initialize();
            }
            _scenarioQueryDAO = new ScenarioQueryDAO(_dbManager);
            _scenarioWriteDAO = new ScenarioWritingDAO(_dbManager);

            this.Scenarios = new ScenarioList(_scenarioQueryDAO, _scenarioWriteDAO, this);
            this.ScenarioGroups = new ScenarioGroupList(_scenarioQueryDAO.DBManager, this.Scenarios, this);
        }

        public IScenarioGroupList ScenarioGroups
        {
            get;
            private set;
        }

        public IScenarioList Scenarios
        {
            get;
            private set;
        }

        public Scenario CreateTemplateScenario(string modelFile, Guid groupId, string sAddScenarioName, string subType, string sRemark)
        {
            Scenario templateScenario = null;
            string sScenarioCode = string.Empty;
            try
            {
                Group inParentScenarioGroup = ScenarioGroups.Get(groupId);
                if (inParentScenarioGroup == null)
                {
                    this.GetType().LogInfo("方案组读取失败，请检查！");
                    return null;
                }

                templateScenario = Scenarios.CreateScenario(modelFile, true, sAddScenarioName, subType, sRemark);
                if (templateScenario == null)
                {
                    this.GetType().LogInfo("方案创建失败！");
                    return null;
                }

                if (!_ImportModel(modelFile, templateScenario))
                {
                    this.GetType().LogInfo("复制方案模型失败！");
                    Scenarios.Delete(templateScenario);
                    return null;
                }

                Group groupScenario = ScenarioGroups.CreateScenarioGroupLinkScenario(inParentScenarioGroup, templateScenario);

                //IModel model = this.GetModel(templateScenario);
                //if (model != null)
                //{
                //    templateScenario.StartTime = model.StartTime;
                //    templateScenario.EndTime = model.EndTime;
                //    Scenarios.Update(templateScenario);
                //    model.Dispose();
                //}
                return templateScenario;
            }
            catch (Exception ex)
            {
                this.GetType().LogError("Failed to create template!", ex);
                if (templateScenario != null)
                {
                    DeleteScenarioAndModel(templateScenario);
                }
                return null;
            }

        }

        public Scenario CreateScenario(Guid templateScenarioId, Guid groupId, string sAddScenarioName, string sStartTime, string sEndTime, string subType, string sRemark)
        {
            string sScenarioCode = string.Empty;
            Scenario newScenario = null;
            try
            {
                //获取模板
                Scenario templateScenario = Scenarios.Get(templateScenarioId);
                if (templateScenario == null)
                {
                    this.GetType().LogInfo("模板读取失败！");
                    return null;
                }

                //检查方案组，如没有则新建失败
                Group inParentScenarioGroup = ScenarioGroups.Get(groupId);//事故
                if (inParentScenarioGroup == null)
                {
                    this.GetType().LogInfo("方案组读取失败，请检查！");
                    return null;
                }

                //新增方案
                newScenario = Scenarios.CreateScenario(templateScenario, null, string.Empty, false, sAddScenarioName, subType, sRemark);
                if (newScenario == null)
                {
                    this.GetType().LogInfo("方案创建失败！");
                    return null;
                }

                string tagetModelDir = ModelFileName(templateScenario);
                if (!_ImportModel(tagetModelDir, newScenario))
                {
                    this.GetType().LogInfo("复制方案模型失败！");
                    Scenarios.Delete(newScenario);
                    return null;
                }

                Group groupScenario = ScenarioGroups.CreateScenarioGroupLinkScenario(inParentScenarioGroup, newScenario);

                newScenario.StartTime = System.Convert.ToDateTime(sStartTime);
                newScenario.EndTime = System.Convert.ToDateTime(sEndTime);
                newScenario.CurrentTime = System.Convert.ToDateTime(sStartTime);
                //if (!UpdateScenarioAndModel(newScenario))
                if(!Scenarios.Update(newScenario))
                {
                    this.GetType().LogInfo("修改模型失败！");
                    DeleteScenarioAndModel(newScenario);
                    return null;
                }
                return newScenario;
            }
            catch (Exception ex)
            {
                this.GetType().LogError(ex.Message, ex);
                if (newScenario != null)
                {
                    DeleteScenarioAndModel(newScenario);
                }
                return null;
            }
        }

        /// <summary>
        /// 从模型文件创建方案
        /// </summary>
        /// <param name="modelFile"></param>
        /// <param name="groupId"></param>
        /// <param name="sAddScenarioName"></param>
        /// <param name="subType"></param>
        /// <param name="sRemark"></param>
        /// <returns></returns>
        public Scenario CreateScenarioFromFile(string modelFile, Guid groupId, string sAddScenarioName, string subType, string sRemark)
        {
            Scenario scenario = null;
            string sScenarioCode = string.Empty;
            try
            {
                //检查方案组
                Group inParentScenarioGroup = null;
                if (groupId != null && groupId != Guid.Empty)
                {
                    inParentScenarioGroup = ScenarioGroups.Get(groupId);//事故
                    if (inParentScenarioGroup == null)
                    {
                        this.GetType().LogInfo("方案组读取失败，请检查！");
                    }
                }

                scenario = Scenarios.CreateScenario(modelFile, false, sAddScenarioName, subType, sRemark);
                if (scenario == null)
                {
                    this.GetType().LogInfo("方案创建失败！");
                    return null;
                }

                if (!_ImportModel(modelFile, scenario))
                {
                    this.GetType().LogInfo("复制方案模型失败！");
                    Scenarios.Delete(scenario);
                    return null;
                }

                Group groupScenario = ScenarioGroups.CreateScenarioGroupLinkScenario(inParentScenarioGroup, scenario);

                //IModel model = this.GetModel(scenario);
                //if (model != null)
                //{
                //    scenario.StartTime = model.StartTime;
                //    scenario.EndTime = model.EndTime;
                //    scenario.CurrentTime = scenario.EndTime.AddDays(-1);
                //    Scenarios.Update(scenario);
                //    model.Dispose();
                //}
                return scenario;
            }
            catch (Exception ex)
            {
                this.GetType().LogError("Failed to create template!", ex);
                if (scenario != null)
                {
                    DeleteScenarioAndModel(scenario);
                }
                return null;
            }

        }

        private bool _ImportModel(string modelFile, Scenario destScenario)
        {
            if (modelFile == string.Empty || !File.Exists(modelFile))
            {
                return false;
            }
            string tagetDir = string.Empty;
            FileInfo fileInfo = new FileInfo(modelFile);
            tagetDir = fileInfo.Directory.FullName;
            if (tagetDir == string.Empty)
            {
                return false;
            }
            else if (new DirectoryInfo(tagetDir).Parent.Name != Scenario.ScenarioFolderName && new DirectoryInfo(tagetDir).Parent.Name != Scenario.TemplateFolderName)//模型文件不在方案根目录下,暂时只考虑上面还有一层的情况
            {
                string sWorkFolderPath = WFAppSettings.GetDefaultConfig().ReadValue("FileRoot"); 
                if (sWorkFolderPath.StartsWith(".\\"))
                {
                    string sCfgDirPath = (new FileInfo(WebFoundation.Settings.WFAppSettings.ConfigFileName)).Directory.FullName;
                    sWorkFolderPath = System.IO.Path.Combine(sCfgDirPath, sWorkFolderPath.Substring(2));
                }
                string sScenarioDirPath = System.IO.Path.Combine(sWorkFolderPath, Scenario.ScenarioFolderName);
                string sTemplateDirPath = System.IO.Path.Combine(sWorkFolderPath, Scenario.TemplateFolderName);
                if (tagetDir.Contains(sScenarioDirPath) || tagetDir.Contains(sTemplateDirPath))//对于来源于模板或方案的modelfile, 模型文件在模型文件夹的子文件夹下的情况，例如Feflow模型 2020-04-28 
                {
                    tagetDir = new DirectoryInfo(tagetDir).Parent.FullName;
                }
                //Note : CreateScenarioFromModel的模型文件目前只能支持模型文件在模型文件夹的根目录形式！2020-04-28 
            }
            string destDir = ScenarioDir(destScenario);

            return _CopyModel(tagetDir, destDir);
        }

        private bool _CopyModel(string tagetDir, string destDir)
        {
            DirectoryInfo srcPath = new DirectoryInfo(tagetDir);
            DirectoryInfo desPath = new DirectoryInfo(destDir);
            return GeneralFunc.CopyDirectory(srcPath, desPath, true, true, false);
        }

        //public IModel GetModel(Scenario scenario)
        //{
        //    IModel model = null;
        //    lock (lockObjet)
        //    {
        //        string sPath = ModelFileName(scenario);
        //        this.GetType().LogInfo("GetModel", sPath);
        //        if (sPath != string.Empty && File.Exists(sPath))
        //        {
        //            enumScenarioType scenarioType = enumScenarioType.Unknown;
        //            if (Enum.GetNames(typeof(enumScenarioType)).Contains(scenario.ModelType))
        //            {
        //                scenarioType = (enumScenarioType)Enum.Parse(typeof(enumScenarioType), scenario.ModelType);
        //            }
        //            string sModelType = GetModelType(scenarioType);
        //            this.GetType().LogInfo("GetModelType", sModelType);
        //            if (sModelType == string.Empty)
        //            {
        //                return null;
        //            }
        //            else
        //            {
        //                if (scenarioType != enumScenarioType.SWMMModel && scenarioType != enumScenarioType.WaterForecastModel && scenarioType != enumScenarioType.EFDCModel)
        //                {
        //                    object[] paras = new object[2];
        //                    paras[0] = sPath;
        //                    if (scenario.ModelSubType == enumSubType.OilSpill.ToString())
        //                    {
        //                        paras[1] = true;
        //                    }
        //                    else
        //                    {
        //                        paras[1] = false;
        //                    }
        //                    model = Activator.CreateInstance(System.Type.GetType(sModelType, true), paras) as IModel;
        //                }
        //            }
        //        }
        //    }
        //    return model;
        //}

        public string ModelDir(Scenario scenario)
        {
            string workFolder = WFAppSettings.GetDefaultConfig().ReadValue(Scenario.WorkFolderAppSettingCode);
            if (workFolder != string.Empty)
            {
                if (scenario.Template == 1)
                {
                    return Path.Combine(workFolder, Scenario.TemplateFolderName, scenario.RelativeFolder);
                }
                else
                {
                    return Path.Combine(workFolder, Scenario.ScenarioFolderName, scenario.RelativeFolder);
                }
            }
            else
            {
                return string.Empty;
            }
        }

        public string ScenarioDir(Scenario scenario)
        {
            string workFolder = WFAppSettings.GetDefaultConfig().ReadValue(Scenario.WorkFolderAppSettingCode);
            if (workFolder != string.Empty)
            {
                if (scenario.Template == 1)
                {
                    return Path.Combine(workFolder, Scenario.TemplateFolderName, scenario.ScenarioCode);
                }
                else
                {
                    return Path.Combine(workFolder, Scenario.ScenarioFolderName, scenario.ScenarioCode);
                }
            }
            else
            {
                return string.Empty;
            }
        }

        public string ModelFileName(Scenario scenario)
        {
            string modelDir = ModelDir(scenario);
            if (modelDir == string.Empty)
            {
                return string.Empty;
            }
            else
            {
                return Path.Combine(modelDir, scenario.ProjectFile);
            }
        }

        //public bool UpdateScenarioAndModel(Scenario scenario)
        //{
        //    if (scenario.ModelType != enumScenarioType.SWMMModel.ToString() && scenario.ModelType != enumScenarioType.EFDCModel.ToString() && scenario.ModelType != enumScenarioType.WaterForecastModel.ToString())//不涉及Model，不需要更新Model
        //    {
        //        IModel model = GetModel(scenario);
        //        if (model == null)
        //        {
        //            return false;
        //        }
        //        model.StartTime = scenario.StartTime;
        //        model.EndTime = scenario.EndTime;
        //        model.Save();
        //        model.Dispose();
        //    }
        //    return Scenarios.Update(scenario);
        //}

        public bool DeleteScenarioAndModel(Scenario scenario)
        {
            bool bSuccess = false;
            try
            {
                string modelDir = ScenarioDir(scenario);
                if (Directory.Exists(modelDir))
                {
                    MHI.Utility.GeneralFunc.DeleteFiles(modelDir);
                    DirectoryInfo[] subDirs = new DirectoryInfo(modelDir).GetDirectories();
                    foreach (DirectoryInfo item in subDirs)
                    {
                        item.Delete();
                    }
                    Directory.Delete(modelDir);
                }
            }
            catch (Exception ex)
            {
                this.GetType().LogError(ex, ex.Message);
            }
            bSuccess = ScenarioGroups.DeleteScenario(scenario);
            return bSuccess;
        }

        public bool DeleteScenarioGroupAndScenario(Group group)
        {
            bool bSuccess = false;
            try
            {
                List<Group> groupList = this.ScenarioGroups.GetScenarioGroupsByGroup(group);
                if (groupList != null && groupList.Count > 0)
                {
                    foreach (Group nextGroup in groupList)
                    {
                        bSuccess = DeleteScenarioGroupAndScenario(nextGroup);
                    }
                }
                else
                {
                    List<Scenario> scenarioList = this.ScenarioGroups.GetScenariosByGroup(group);
                    if (scenarioList != null && scenarioList.Count > 0)
                    {
                        foreach (Scenario scenario in scenarioList)
                        {
                            bSuccess = DeleteScenarioAndModel(scenario);
                        }
                    }
                }
                bSuccess = this.ScenarioGroups.Delete(group);
            }
            catch (Exception ex)
            {
                this.GetType().LogError(ex, ex.Message);
            }
            return bSuccess;
        }

        protected override void Dispose(bool disposing)
        {
            if (!this.disposed && disposing)
            {
                this._dbManager.Dispose();
            }
            base.Dispose(disposing);
        }
    }
}
